
MarketActor subclass: #CheckoutCounter
  instanceVariableNames: 
    'checker bagger customers nowServing '
  classVariableNames: 
    'MaxCustomers '
  poolDictionaries: '' !

!CheckoutCounter class methods !

imageName
    ^'Counter'.!

initialize
    MaxCustomers isNil ifTrue:[MaxCustomers := 3].!

maxCustomers
    self initialize.
    ^MaxCustomers.!

maxCustomers:aNumber
    MaxCustomers := aNumber.!

new
    self initialize.
    ^super new.!

priority
    ^3.! !


!CheckoutCounter methods !

addCustomer
    |aCustomer|
    aCustomer := self receive.
    running
        ifTrue:[
            customers add:aCustomer.
            self length == 1
                ifTrue:[self nextCustomer]].!

checkoutPosition
        "Answer a Point, the checkout position."
    ^position - (Customer width @ 0).!

display
    super display.
    checker display.
    bagger display.!

endOfLinePosition
        "Answer a Point, the end of the checkout line."
    ^position
        - (Customer width
            @ (customers size + 1 * Customer height)).!

exitPosition
        "Answer a Point, the exit position."
    ^position + ((0 - Customer width) @ self height).!

initialize
    checker := Checker new.
    bagger  := Bagger new.
    checker bagger:bagger.
    bagger  checker:checker.
    customers := OrderedCollection new:MaxCustomers.
    super initialize.!

length
    ^customers size
        + (nowServing isNil ifTrue:[0] ifFalse:[1]).!

nextCustomer
    running
        ifTrue:[
            customers isEmpty
                ifTrue: [nowServing := nil]
                ifFalse:[
                    nowServing := customers removeFirst.
                    self send:#moveToCheckout
                            to:nowServing
                            with:checker.
                    customers do:[:aCustomer|
                        aCustomer isNil
                            ifFalse:[
                                self send:#moveForward to:aCustomer]]]].!

position:aPoint
    super position:aPoint.
    checker position:aPoint
                        + ((self width // 2)
                            @ (self height // 4)).
    bagger position:aPoint + (0 @ self height * 3 // 4).!

release
    bagger release.  checker    release.  nowServing release.
    bagger := nil.   checker := nil.      nowServing := nil.

    [customers isEmpty] whileFalse:[customers removeFirst release].
    customers release.  customers  := nil.  super release.!

shutdown
    |semaphore|
    self update:0.
    semaphore := Semaphore new.
    customers do:[:aCustomer|
            aCustomer stop:semaphore.
            semaphore wait].
    nowServing isNil
        ifFalse:[
            nowServing stop:semaphore.
            semaphore wait].
    checker isNil
        ifFalse:[
            checker stop:semaphore.
            semaphore wait].
    bagger isNil
        ifFalse:[
            bagger stop:semaphore.
            semaphore wait].
    super shutdown.!

start
    super start.
    bagger start.
    checker start.!

update
    |aValue|
    ((aValue := self receive) isKindOf:Number)
        ifTrue:[self update:aValue].!

update:aValue
    |fieldWidth textPosition extent|
    textPosition :=
        position  + ((self width // 2)
                        @ ((SysFont height + 2) negated)).
    fieldWidth := 3.
    extent := (SysFont width * fieldWidth)
                @ SysFont height.
    aValue == 0
        ifTrue: [Display white:(textPosition extent:extent)]
        ifFalse:[(aValue printString flushedRightIn:fieldWidth)
                        displayAt:textPosition].! !
